package edu.poly.cs9223.ass2.ec2.tools;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.services.autoscaling.AmazonAutoScalingClient;
import com.amazonaws.services.autoscaling.model.AutoScalingGroup;
import com.amazonaws.services.autoscaling.model.DeleteAutoScalingGroupRequest;
import com.amazonaws.services.autoscaling.model.DeleteLaunchConfigurationRequest;
import com.amazonaws.services.autoscaling.model.DescribeAutoScalingGroupsRequest;
import com.amazonaws.services.autoscaling.model.DescribeAutoScalingGroupsResult;
import com.amazonaws.services.autoscaling.model.DescribeLaunchConfigurationsResult;
import com.amazonaws.services.autoscaling.model.LaunchConfiguration;
import com.amazonaws.services.cloudfront.AmazonCloudFrontClient;
import com.amazonaws.services.cloudfront.model.Aliases;
import com.amazonaws.services.cloudfront.model.CacheBehaviors;
import com.amazonaws.services.cloudfront.model.CookiePreference;
import com.amazonaws.services.cloudfront.model.DefaultCacheBehavior;
import com.amazonaws.services.cloudfront.model.DeleteDistributionRequest;
import com.amazonaws.services.cloudfront.model.DeleteStreamingDistributionRequest;
import com.amazonaws.services.cloudfront.model.DistributionConfig;
import com.amazonaws.services.cloudfront.model.DistributionSummary;
import com.amazonaws.services.cloudfront.model.ForwardedValues;
import com.amazonaws.services.cloudfront.model.GetDistributionConfigRequest;
import com.amazonaws.services.cloudfront.model.GetDistributionConfigResult;
import com.amazonaws.services.cloudfront.model.GetDistributionRequest;
import com.amazonaws.services.cloudfront.model.GetDistributionResult;
import com.amazonaws.services.cloudfront.model.GetStreamingDistributionConfigRequest;
import com.amazonaws.services.cloudfront.model.GetStreamingDistributionConfigResult;
import com.amazonaws.services.cloudfront.model.GetStreamingDistributionRequest;
import com.amazonaws.services.cloudfront.model.GetStreamingDistributionResult;
import com.amazonaws.services.cloudfront.model.ItemSelection;
import com.amazonaws.services.cloudfront.model.ListDistributionsRequest;
import com.amazonaws.services.cloudfront.model.ListDistributionsResult;
import com.amazonaws.services.cloudfront.model.ListStreamingDistributionsRequest;
import com.amazonaws.services.cloudfront.model.ListStreamingDistributionsResult;
import com.amazonaws.services.cloudfront.model.LoggingConfig;
import com.amazonaws.services.cloudfront.model.Origin;
import com.amazonaws.services.cloudfront.model.Origins;
import com.amazonaws.services.cloudfront.model.StreamingDistributionConfig;
import com.amazonaws.services.cloudfront.model.StreamingDistributionSummary;
import com.amazonaws.services.cloudfront.model.TrustedSigners;
import com.amazonaws.services.cloudfront.model.UpdateDistributionRequest;
import com.amazonaws.services.cloudfront.model.UpdateDistributionResult;
import com.amazonaws.services.cloudfront.model.UpdateStreamingDistributionRequest;
import com.amazonaws.services.cloudfront.model.UpdateStreamingDistributionResult;
import com.amazonaws.services.cloudwatch.AmazonCloudWatchClient;
import com.amazonaws.services.cloudwatch.model.DescribeAlarmsResult;
import com.amazonaws.services.cloudwatch.model.DisableAlarmActionsRequest;
import com.amazonaws.services.cloudwatch.model.MetricAlarm;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.Address;
import com.amazonaws.services.ec2.model.AuthorizeSecurityGroupIngressRequest;
import com.amazonaws.services.ec2.model.CreateKeyPairRequest;
import com.amazonaws.services.ec2.model.CreateKeyPairResult;
import com.amazonaws.services.ec2.model.CreateSecurityGroupRequest;
import com.amazonaws.services.ec2.model.CreateSecurityGroupResult;
import com.amazonaws.services.ec2.model.DeleteKeyPairRequest;
import com.amazonaws.services.ec2.model.DeleteSecurityGroupRequest;
import com.amazonaws.services.ec2.model.DeleteSnapshotRequest;
import com.amazonaws.services.ec2.model.DeregisterImageRequest;
import com.amazonaws.services.ec2.model.DescribeAddressesResult;
import com.amazonaws.services.ec2.model.DescribeImagesRequest;
import com.amazonaws.services.ec2.model.DescribeImagesResult;
import com.amazonaws.services.ec2.model.DescribeInstanceAttributeRequest;
import com.amazonaws.services.ec2.model.DescribeInstanceStatusRequest;
import com.amazonaws.services.ec2.model.DescribeInstanceStatusResult;
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesResult;
import com.amazonaws.services.ec2.model.DescribeKeyPairsResult;
import com.amazonaws.services.ec2.model.DescribeSecurityGroupsRequest;
import com.amazonaws.services.ec2.model.DescribeSecurityGroupsResult;
import com.amazonaws.services.ec2.model.DescribeSnapshotsRequest;
import com.amazonaws.services.ec2.model.DescribeSnapshotsResult;
import com.amazonaws.services.ec2.model.Filter;
import com.amazonaws.services.ec2.model.Image;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.InstanceStatus;
import com.amazonaws.services.ec2.model.IpPermission;
import com.amazonaws.services.ec2.model.KeyPair;
import com.amazonaws.services.ec2.model.KeyPairInfo;
import com.amazonaws.services.ec2.model.ReleaseAddressRequest;
import com.amazonaws.services.ec2.model.Reservation;
import com.amazonaws.services.ec2.model.RunInstancesRequest;
import com.amazonaws.services.ec2.model.RunInstancesResult;
import com.amazonaws.services.ec2.model.SecurityGroup;
import com.amazonaws.services.ec2.model.Snapshot;
import com.amazonaws.services.ec2.model.TerminateInstancesRequest;
import com.amazonaws.services.rds.AmazonRDSClient;
import com.amazonaws.services.rds.model.DBInstance;
import com.amazonaws.services.rds.model.DeleteDBInstanceRequest;
import com.amazonaws.services.rds.model.DescribeDBInstancesResult;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.s3.model.DeleteObjectRequest;
import com.amazonaws.services.s3.model.DeleteObjectsRequest;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import com.amazonaws.services.sns.AmazonSNSClient;

/**
 * (1)
 * 
 * @author Kevin Zhao
 * 
 */
public class AWSTool {

	private static AmazonEC2 amazonEC2Client = null;
	private static AmazonAutoScalingClient amazonAutoScalingClient = null;
	private static AmazonCloudWatchClient amazonCloudWatchClient = null;
	private static AmazonSNSClient amazonSNSClient = null;
	private static AmazonRDSClient amazonRDSClient;
	private static AmazonCloudFrontClient amazonCloudFrontClient;
	private static AmazonS3 amazonS3Client;
	private static int COMM_RETRY_LIMIT = 1;// retry limit of commnication with
	public static int COMM_RETRY_WAITING_TIME = 4 * 1000;// 6s waiting
	AWSCredentials credentials = null;
	private static final String EC2_INSTANCE_TYPE = "t1.micro";
	private static final String EC2_AMI_ID = "ami-3275ee5b";

	public static String AWS_NAMESPACE = "edu.poly.cs9223.0488541.";
	public static String AWS_S3_END_POINT_NAME = "s3.amazonaws.com";
	public static String AWS_RDS_END_POINT_NAME = "rds.us-east-1.amazonaws.com";
	public static String AWS_CLOUDFRONT_END_POINT_NAME = "cloudfront.amazonaws.com";

	private static int DEFAULT_SSH_PORT = 22;
	private static int DEFAULT_TOMCAT_PORT = 8080;
	Logger logger = LoggerFactory.getLogger(AWSTool.class);

	public AWSTool() {

		InputStream credentialsAsStream = Thread.currentThread()
				.getContextClassLoader()
				.getResourceAsStream("AwsCredentials.properties");
		try {
			credentials = new PropertiesCredentials(credentialsAsStream);
		} catch (IOException e) {
			logger.error("Please put your AwsCredentials.properties file into the classpath and run the program again.");
		}
		// 2. To create and initialize an Amazon clients
		amazonEC2Client = new AmazonEC2Client(credentials);
		amazonAutoScalingClient = new AmazonAutoScalingClient(credentials);
		amazonCloudWatchClient = new AmazonCloudWatchClient(credentials);
		amazonSNSClient = new AmazonSNSClient(credentials);

		amazonRDSClient = new AmazonRDSClient(credentials);
		amazonRDSClient.setEndpoint(AWS_RDS_END_POINT_NAME);

		amazonCloudFrontClient = new AmazonCloudFrontClient(credentials);
		amazonCloudFrontClient.setEndpoint(AWS_CLOUDFRONT_END_POINT_NAME);

		amazonS3Client = new AmazonS3Client(credentials);
	}

	public String createEC2Instance(String keyName, String securityGroupName) {
		RunInstancesRequest runInstancesRequest = new RunInstancesRequest();
		runInstancesRequest.withImageId(EC2_AMI_ID)
				.withInstanceType(EC2_INSTANCE_TYPE).withMinCount(1)
				.withMaxCount(1).withKeyName(keyName)
				.withSecurityGroups(securityGroupName);

		RunInstancesResult runInstancesResult = amazonEC2Client
				.runInstances(runInstancesRequest);

		Instance instance = runInstancesResult.getReservation().getInstances()
				.get(0);
		logger.debug("ec2 instance [{}] has been created",
				instance.getInstanceId());

		logger.info("waiting for instance [{}] to be in running state",
				instance.getInstanceId());

		try {
			Thread.sleep(COMM_RETRY_WAITING_TIME);
			DescribeInstanceStatusResult descInceResult = amazonEC2Client
					.describeInstanceStatus(new DescribeInstanceStatusRequest()
							.withInstanceIds(instance.getInstanceId()));

			InstanceStatus status = null;
			while (descInceResult.getInstanceStatuses().size() == 0
					|| !"running".equals(status.getInstanceState().getName())) {

				System.out.print("*");
				Thread.sleep(COMM_RETRY_WAITING_TIME);
				descInceResult = amazonEC2Client
						.describeInstanceStatus(new DescribeInstanceStatusRequest()
								.withInstanceIds(instance.getInstanceId()));
				if (descInceResult.getInstanceStatuses().size() != 0)
					status = descInceResult.getInstanceStatuses().get(0);
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		DescribeInstancesResult descInstanceResult = amazonEC2Client
				.describeInstances(new DescribeInstancesRequest()
						.withInstanceIds(instance.getInstanceId()));
		instance = descInstanceResult.getReservations().get(0).getInstances()
				.get(0);
		logger.debug("ec2 instance [{}] is ready,host dns is [{}] ",
				instance.getInstanceId(), instance.getPublicDnsName());
		return instance.getPublicDnsName();

	}

	public String createEC2KeyPair(String keyName) {

		DescribeKeyPairsResult result = amazonEC2Client.describeKeyPairs();
		List<KeyPairInfo> keys = result.getKeyPairs();
		for (KeyPairInfo key : keys) {
			if (key.getKeyName().equals(keyName)) {
				// delete the pre-existed one
				DeleteKeyPairRequest deleteKeyPairRequest = new DeleteKeyPairRequest();
				deleteKeyPairRequest.withKeyName(keyName);
				amazonEC2Client.deleteKeyPair(deleteKeyPairRequest);
			}
		}
		// create new one
		CreateKeyPairRequest createKeyPairRequest = new CreateKeyPairRequest();

		createKeyPairRequest.withKeyName(keyName);

		CreateKeyPairResult createKeyPairResult = amazonEC2Client
				.createKeyPair(createKeyPairRequest);

		KeyPair keyPair = new KeyPair();

		keyPair = createKeyPairResult.getKeyPair();

		String privateKey = keyPair.getKeyMaterial();
		// System.out.println("private key:" + privateKey);

		String priaveKeyPath = keyName + ".pem";

		writeToFile(privateKey, priaveKeyPath);

		logger.debug("keypair [{}] has been created", priaveKeyPath);
		return priaveKeyPath;

	}

	private void writeToFile(String text, String path) {
		FileWriter fileWriter = null;
		try {
			String content = text;
			File newTextFile = new File(path);
			fileWriter = new FileWriter(newTextFile);
			fileWriter.write(content);
			fileWriter.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		} finally {
			try {
				fileWriter.close();
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
	}

	public void createEC2SecurityGroup(String securityGroupName) {

		DescribeSecurityGroupsResult result = amazonEC2Client
				.describeSecurityGroups();
		List<SecurityGroup> groups = result.getSecurityGroups();
		for (SecurityGroup group : groups) {
			if (group.getGroupName().equals(securityGroupName)) {
				// delete the pre-existed one
				// DeleteSecurityGroupRequest deleteSecurityGroupRequest = new
				// DeleteSecurityGroupRequest();
				// deleteSecurityGroupRequest.withGroupName(groupName);
				// amazonEC2Client.deleteSecurityGroup(deleteSecurityGroupRequest);
				logger.debug("securitygroup [{}] has existeded",
						securityGroupName);
				return;
			}
		}

		// create new one
		CreateSecurityGroupRequest createSecurityGroupRequest = new CreateSecurityGroupRequest();

		createSecurityGroupRequest.withGroupName(securityGroupName)
				.withDescription("security group created by java");
		CreateSecurityGroupResult createSecurityGroupResult = amazonEC2Client
				.createSecurityGroup(createSecurityGroupRequest);

		// Before starting an Amazon EC2 instance, you next need to authorize
		// security group ingress and create a key pair to allow you to log into
		// your instance.

		// 4. To authorize security group ingress
		List<String> ipRanges = new ArrayList<String>();
		ipRanges.add("0.0.0.0/0");

		ArrayList<IpPermission> ipPermissions = new ArrayList<IpPermission>();
		IpPermission sshPermission = new IpPermission();
		sshPermission.setIpProtocol("tcp");
		sshPermission.setFromPort(new Integer(DEFAULT_SSH_PORT));
		sshPermission.setToPort(new Integer(DEFAULT_SSH_PORT));
		sshPermission.setIpRanges(ipRanges);

		IpPermission tomcatPermission = new IpPermission();
		tomcatPermission.setIpProtocol("tcp");
		tomcatPermission.setFromPort(new Integer(DEFAULT_TOMCAT_PORT));
		tomcatPermission.setToPort(new Integer(DEFAULT_TOMCAT_PORT));
		tomcatPermission.setIpRanges(ipRanges);

		ipPermissions.add(sshPermission);
		ipPermissions.add(tomcatPermission);

		try {
			// Authorize the ports to the used.
			AuthorizeSecurityGroupIngressRequest ingressRequest = new AuthorizeSecurityGroupIngressRequest(
					securityGroupName, ipPermissions);
			amazonEC2Client.authorizeSecurityGroupIngress(ingressRequest);
		} catch (AmazonServiceException ase) {
			// Ignore because this likely means the zone has already been
			// authorized.
			logger.error("ERROR {}", ase.getMessage());
		}
		logger.debug("securitygroup [{}] has been created", securityGroupName);

	}

	public void cleanUpAll() throws InterruptedException {
		logger.info("cleanning up start!");
		// realease elasticIP
		releaseAllElasticIP();

		// delete keys
		logger.info("delete all key pairs");
		DescribeKeyPairsResult descKeyPairsResult = amazonEC2Client
				.describeKeyPairs();
		for (KeyPairInfo keyInfo : descKeyPairsResult.getKeyPairs()) {
			amazonEC2Client.deleteKeyPair(new DeleteKeyPairRequest()
					.withKeyName(keyInfo.getKeyName()));
		}

		// delete auto scaling group
		logger.info("delete auto scaling group");
		List<AutoScalingGroup> groups = getAllScalingGroup();
		for (AutoScalingGroup group : groups) {
			deleteAutoScalingGroup(group.getAutoScalingGroupName());
		}

		// suspendMonitoring
		logger.info("disable cloud watch alarms");
		DescribeAlarmsResult alarmsResult = amazonCloudWatchClient
				.describeAlarms();
		List<MetricAlarm> alarms = alarmsResult.getMetricAlarms();
		if (alarms.size() > 0) {
			List<String> alarmNames = new ArrayList<String>();
			for (MetricAlarm alarm : alarms) {
				alarmNames.add(alarm.getAlarmName());
			}
			DisableAlarmActionsRequest disableAlarmActionsRequest = new DisableAlarmActionsRequest();
			disableAlarmActionsRequest.withAlarmNames(alarmNames);
			amazonCloudWatchClient
					.disableAlarmActions(disableAlarmActionsRequest);
		}

		// termiate all instances
		logger.info("termiate all ec2 instances");
		List<String> instanceIds = getAllInstanceIdsWithStatusFilter("running",
				"stopping", "stopped", "pending");
		if (instanceIds.size() > 0) {
			TerminateInstancesRequest terminateInstancesARequest = new TerminateInstancesRequest();
			terminateInstancesARequest.withInstanceIds(instanceIds);
			amazonEC2Client.terminateInstances(terminateInstancesARequest);
			// waiting for terminating instances...it will usually take 30
			// seconds
			// or so...
			int notTerminated = 100;
			logger.debug("waiting for terminating instances...it will usually take 30 seconds or so...");
			while (notTerminated != 0) {

				System.out.print("*");
				Thread.sleep(COMM_RETRY_WAITING_TIME);// it will
														// usually
														// take
														// 30s
														// more
														// to
														// terminate
														// all
														// instances

				notTerminated = getAllInstanceIdsWithStatusFilter("pending",
						"running", "shutting-down", " stopping", "stopped")
						.size();
			}
		}

		// delte all sg
		logger.info("delete all security groups");
		DescribeSecurityGroupsResult descGroupsResult = amazonEC2Client
				.describeSecurityGroups();

		for (SecurityGroup group : descGroupsResult.getSecurityGroups()) {
			if (group.getGroupName().equals("default"))
				continue;
			DeleteSecurityGroupRequest deleteSecurityGroupRequest = new DeleteSecurityGroupRequest();
			deleteSecurityGroupRequest.withGroupName(group.getGroupName());
			amazonEC2Client.deleteSecurityGroup(deleteSecurityGroupRequest);
		}

		logger.info("delete auto scaling launch configuration");
		// delete launch configuration
		DescribeLaunchConfigurationsResult lcResult = amazonAutoScalingClient
				.describeLaunchConfigurations();
		List<LaunchConfiguration> lcs = lcResult.getLaunchConfigurations();
		for (LaunchConfiguration lc : lcs) {
			DeleteLaunchConfigurationRequest deleteLaunchConfigurationRequest = new DeleteLaunchConfigurationRequest();
			String launchConfigurationName = lc.getLaunchConfigurationName();
			deleteLaunchConfigurationRequest
					.withLaunchConfigurationName(launchConfigurationName);
			amazonAutoScalingClient
					.deleteLaunchConfiguration(deleteLaunchConfigurationRequest);

		}

		logger.info("delete all ami");
		// delete ami
		DescribeImagesRequest describeImagesRequest = new DescribeImagesRequest();
		describeImagesRequest.withOwners("self");
		DescribeImagesResult imagesResult = amazonEC2Client
				.describeImages(describeImagesRequest);
		List<Image> images = imagesResult.getImages();
		for (Image image : images) {
			DeregisterImageRequest deregisterImageRequest = new DeregisterImageRequest();
			String imageId = image.getImageId();
			deregisterImageRequest.withImageId(imageId);
			amazonEC2Client.deregisterImage(deregisterImageRequest);
		}

		logger.info("delete all snapshots");
		// deleteAllSnapshots
		deleteAllSnapshots();
		logger.info("delete RDS instances");
		// delete all RDS instance
		DescribeDBInstancesResult descDBResult = amazonRDSClient
				.describeDBInstances();
		for (DBInstance dbInstance : descDBResult.getDBInstances()) {
			if (!"deleting".equals(dbInstance.getDBInstanceStatus())) {
				amazonRDSClient.deleteDBInstance(new DeleteDBInstanceRequest(
						dbInstance.getDBInstanceIdentifier())
						.withSkipFinalSnapshot(true));
			}

		}

		// delete all s3 buckets
		logger.info("delete all s3 buckets");
		for (Bucket bucket : amazonS3Client.listBuckets()) {
			ObjectListing listObjsResult = amazonS3Client.listObjects(bucket
					.getName());
			for (S3ObjectSummary s3Obj : listObjsResult.getObjectSummaries()) {
				amazonS3Client.deleteObject(new DeleteObjectRequest(bucket
						.getName(), s3Obj.getKey()));
			}
			// amazonS3Client.deleteObjects(new
			// DeleteObjectsRequest(bucket.getName()));
			amazonS3Client.deleteBucket(bucket.getName());
		}

		// delete all cloudfront distribution
		logger.info("delete all cloudfront download distribution");
		ListDistributionsResult listDistResult = amazonCloudFrontClient
				.listDistributions(new ListDistributionsRequest());
		for (DistributionSummary dist : listDistResult.getDistributionList()
				.getItems()) {
			GetDistributionConfigResult distCfgResut = amazonCloudFrontClient
					.getDistributionConfig(new GetDistributionConfigRequest(
							dist.getId()));
			String distETag = distCfgResut.getETag();
			DistributionConfig distCfg = distCfgResut.getDistributionConfig();
			distCfg.withEnabled(false);
			// disable
			UpdateDistributionResult updateResult = amazonCloudFrontClient
					.updateDistribution(new UpdateDistributionRequest()
							.withId(dist.getId()).withIfMatch(distETag)
							.withDistributionConfig(distCfg));
			distETag = updateResult.getETag();
			// delete
			try {
				amazonCloudFrontClient
						.deleteDistribution(new DeleteDistributionRequest()
								.withIfMatch(distETag).withId(dist.getId()));
			} catch (AmazonServiceException e) {
				logger.error(e.toString());
				// e.printStackTrace();
			} catch (AmazonClientException e) {
				logger.error(e.toString());
				// e.printStackTrace();
			}
		}

		logger.info("delete all cloudfront stream distribution");
		ListStreamingDistributionsResult listStreamResult = amazonCloudFrontClient
				.listStreamingDistributions(new ListStreamingDistributionsRequest());
		for (StreamingDistributionSummary stream : listStreamResult
				.getStreamingDistributionList().getItems()) {
			GetStreamingDistributionConfigResult streamCfgResult = amazonCloudFrontClient
					.getStreamingDistributionConfig(new GetStreamingDistributionConfigRequest(
							stream.getId()));
			StreamingDistributionConfig streamCfg = streamCfgResult
					.getStreamingDistributionConfig();
			streamCfg.withEnabled(false);
			String streamETag = streamCfgResult.getETag();
			// disable
			UpdateStreamingDistributionResult streamUpdateResult = amazonCloudFrontClient
					.updateStreamingDistribution(new UpdateStreamingDistributionRequest()
							.withId(stream.getId()).withIfMatch(streamETag)
							.withStreamingDistributionConfig(streamCfg));
			streamETag = streamUpdateResult.getETag();
			// delete
			try {
				amazonCloudFrontClient
						.deleteStreamingDistribution(new DeleteStreamingDistributionRequest(
								stream.getId(), streamETag));
			} catch (AmazonServiceException e) {
				logger.error(e.toString());
				// e.printStackTrace();
			} catch (AmazonClientException e) {
				logger.error(e.toString());
				// e.printStackTrace();
			}
		}

		logger.info("clean up all done!");
	}

	private void releaseAllElasticIP() {
		DescribeAddressesResult descElasticIpsResult = amazonEC2Client
				.describeAddresses();
		logger.debug("you have {} available elastic ip", descElasticIpsResult
				.getAddresses().size());
		for (Address elasticIp : descElasticIpsResult.getAddresses()) {
			logger.debug("releasing elastic ip [{}]", elasticIp.getPublicIp());
			ReleaseAddressRequest releaseAddressRequest = new ReleaseAddressRequest();
			releaseAddressRequest.withPublicIp(elasticIp.getPublicIp());
			amazonEC2Client.releaseAddress(releaseAddressRequest);
			logger.debug("successfully released elastic ip [{}]",
					elasticIp.getPublicIp());
		}
	}

	private List<AutoScalingGroup> getAllScalingGroup() {
		DescribeAutoScalingGroupsResult describeAutoScalingGroupResult = amazonAutoScalingClient
				.describeAutoScalingGroups();
		List<AutoScalingGroup> groups = describeAutoScalingGroupResult
				.getAutoScalingGroups();

		return groups;
	}

	private void deleteAutoScalingGroup(String groupName)
			throws InterruptedException {
		logger.debug("delete auto scaling group ");

		if (getAutoScalingGroupAmount(groupName) == 0)
			return;
		// delete the pre-existed one
		DeleteAutoScalingGroupRequest deleteAutoScalingGroupRequest = new DeleteAutoScalingGroupRequest();
		deleteAutoScalingGroupRequest.withAutoScalingGroupName(groupName)
				.withForceDelete(true);
		amazonAutoScalingClient
				.deleteAutoScalingGroup(deleteAutoScalingGroupRequest);
		logger.debug("deleting auto scaling group of [{}] done", groupName);

		// wait until auto scaling group deletion complete
		boolean deletionDone = getAutoScalingGroupAmount(groupName) == 0;
		while (!deletionDone) {
			logger.debug("wait for deletion of auto scaling group [{}] done",
					groupName);
			Thread.sleep(COMM_RETRY_WAITING_TIME);
			deletionDone = getAutoScalingGroupAmount(groupName) == 0;
		}
	}

	private static int getAutoScalingGroupAmount(String groupName) {
		DescribeAutoScalingGroupsRequest describeAutoScalingGroupsRequest = new DescribeAutoScalingGroupsRequest();
		describeAutoScalingGroupsRequest.withAutoScalingGroupNames(groupName);
		DescribeAutoScalingGroupsResult describeAutoScalingGroupResult = amazonAutoScalingClient
				.describeAutoScalingGroups(describeAutoScalingGroupsRequest);
		List<AutoScalingGroup> groups = describeAutoScalingGroupResult
				.getAutoScalingGroups();
		return groups.size();
	}

	private List<String> getAllInstanceIdsWithStatusFilter(String... statuses) {
		List<String> instanceIds = new ArrayList<String>();
		DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest();
		Filter filters = new Filter();
		filters.setName("instance-state-name");
		Collection<String> values = Arrays.asList(statuses);
		filters.setValues(values);
		describeInstancesRequest.withFilters(filters);
		DescribeInstancesResult descInstanceResult = amazonEC2Client
				.describeInstances(describeInstancesRequest);

		List<Reservation> reservations = descInstanceResult.getReservations();

		for (Reservation reservation : reservations) {
			List<Instance> instances = reservation.getInstances();
			for (Instance instance : instances) {
				instanceIds.add(instance.getInstanceId());
			}
		}
		return instanceIds;
	}

	private void deleteAllSnapshots() {
		logger.info("looking for snapshots");
		DescribeSnapshotsRequest describeSnapshotsRequest = new DescribeSnapshotsRequest();
		describeSnapshotsRequest.withOwnerIds("self");
		DescribeSnapshotsResult descSnapshotsResult = amazonEC2Client
				.describeSnapshots(describeSnapshotsRequest);
		List<Snapshot> snapshots = descSnapshotsResult.getSnapshots();
		if (snapshots.size() == 0)
			return;
		for (Snapshot snapshot : snapshots) {
			logger.info("delete snapshot:{}", snapshot.getSnapshotId());
			DeleteSnapshotRequest deleteSnapshotRequest = new DeleteSnapshotRequest();
			deleteSnapshotRequest.withSnapshotId(snapshot.getSnapshotId());
			amazonEC2Client.deleteSnapshot(deleteSnapshotRequest);
		}
	}

	private boolean hasRunningInstances(String securityGroupName)
			throws InterruptedException {
		int numberOfRunningInstances = checkInstancesWithSpecificStatus(
				securityGroupName, "running");
		if (numberOfRunningInstances == 0) {
			logger.debug(
					"Security group [{}] has no running instances for now",
					securityGroupName);
			return false;
		}
		return true;

	}

	private int checkInstancesWithSpecificStatus(String securityGroupName,
			String... statuses) throws InterruptedException {
		logger.debug("check Instances with {} status in security group [{}]",
				statuses, securityGroupName);
		DescribeInstancesRequest describeInstancesRequest = new DescribeInstancesRequest();
		Filter stateFilter = new Filter();
		stateFilter.setName("instance-state-name");
		Collection<String> values = Arrays.asList(statuses);
		stateFilter.setValues(values);
		Filter groupNameFilter = new Filter();
		groupNameFilter.setName("instance.group-name");
		groupNameFilter.setValues(Arrays.asList(securityGroupName));
		describeInstancesRequest.withFilters(stateFilter).withFilters(
				stateFilter, groupNameFilter);
		DescribeInstancesResult descInstanceResult = amazonEC2Client
				.describeInstances(describeInstancesRequest);

		int instanceAmount = 0;

		List<Reservation> reservations = descInstanceResult.getReservations();
		for (Reservation reservation : reservations) {
			instanceAmount += reservation.getInstances().size();
		}

		return instanceAmount;
	}

	public static void main(String[] args) throws Exception {
		System.out
				.println("Please insert your Amazon secretKey and accessKey in the AwsCredentials.properties before running the program");
		System.out
				.println("you can get your AWS Credentials from http://aws.amazon.com/security-credentials");
		System.out
				.println("==========================AWS Manage tools by Yuan Zhao(0488541)===========================================");
		System.out.println("[1]:SETUP EC2 instance as a web server");
		System.out
				.println("[2]:clean up all(!!!!This option will delete all the stuffs on your account!!!!)");
		System.out.println("[3]:Test");
		System.out
				.println("=======================================================================================================================");
		System.out.println("please enther the option number here===>:");

		AWSTool awsTool = new AWSTool();
		JSSHTool sshTool = new JSSHTool();

		String option = readFromConsole();
		if ("1".equals(option)) {
			// 1. create instance
			String priaveKeyPath = awsTool
					.createEC2KeyPair("cs9223_assignment2_keypair");
			awsTool.createEC2SecurityGroup("cs9223_assignment2_sg");
			String host = awsTool.createEC2Instance(
					"cs9223_assignment2_keypair", "cs9223_assignment2_sg");
			// 2.SSH into instance
			sshTool.sshLogin("ec2-user", host, priaveKeyPath, DEFAULT_SSH_PORT);
			// 3.install tomcat and sertup tomcat
			sshTool.executeShellScript(new File("setup.sh"));
			// 5.upload war file&conf file
			sshTool.uploadFile("/var/lib/tomcat6/webapps/", "myTube.war");
			sshTool.uploadFile("/usr/share/tomcat6/conf", "tomcat-users.xml");
			// 6.post set up
			sshTool.executeShellScript(new File("post_setup.sh"));

			// 7.print Web App URL
			awsTool.logger.info("MYTube App is ready at:{}", host + ":"
					+ DEFAULT_TOMCAT_PORT + "/myTube");
			// 8.open shell
			sshTool.openShell();
		} else if ("2".equals(option)) {
			awsTool.cleanUpAll();
		} else if ("3".equals(option)) {
			String host = "ec2-54-234-167-11.compute-1.amazonaws.com";
			sshTool.sshLogin("ec2-user", host,
					"cs9223_assignment2_keypair.pem", DEFAULT_SSH_PORT);
			// 3.install tomcat and sertup tomcat
			sshTool.executeShellScript(new File("setup.sh"));
			// 5.upload war file&conf file
			sshTool.uploadFile("/var/lib/tomcat6/webapps/", "myTube.war");
			sshTool.uploadFile("/usr/share/tomcat6/conf", "tomcat-users.xml");
			// 6.post set up
			sshTool.executeShellScript(new File("post_setup.sh"));

			// 7.print Web App URL
			awsTool.logger.info("MYTube App is ready at:{}", host + ":"
					+ DEFAULT_TOMCAT_PORT + "/myTube");
			awsTool.logger.info("It might takes more than 2 minutes when you visit MyTube for the first time,because it will create RDS instance and wait until RDS instance become avaliable.");

			// sshTool.openShell();
		} else {
			System.out.println("invalid option number");
		}
	}

	public static String readFromConsole() {

		InputStreamReader isr = new InputStreamReader(System.in);
		BufferedReader br = new BufferedReader(isr);

		try {
			String line = null;
			while (!(line = br.readLine()).equals("")) {
				return line;
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

}
